<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * share_page.php
 * 分享/下载页面的控制器
 * @author  :  LM
 * @author  :  Skiychan <developer@zzzzy.com>
 * @created :  2015/4/16
 * @modified:  
 * @version :  0.0.1
 */
class Share_page extends CI_Controller {
    private $share_info = array();
    private $status = TRUE;

    public function __construct() {
        parent::__construct();
        $this->load->library('user_agent');
        $this->load->service('share_page_service');
        $this->load->service('user_files_service');
        $this->load->service('share_service');
        $this->status = $this->is_share();
    }

    /**
     * 判断是否有密码/或者是本人
     * @return bool
     */
    private function is_share() {
        $code = $this->input->get('code');
        if (!$code) {
            //是否为post请求
            $code = $this->input->post('code');
            //通过路由后不存在uuid可以通过URI片段获取
            if (!$code)
                $code = $this->uri->segment(2);
        }

        if ($this->agent->is_mobile()) {
            $platform = $this->input->get("platform");
            $refresh = time();
            $local_url = sprintf("/m/download.html?_=%s#index/index?code=%s&platform=%s",
                $refresh,
                $code,
                $platform);
            return redirect($local_url);
        }

        //如果不存在code则
        if (!$code) return FALSE;
        $code = substr($code,0,8);

        $share_res = $this->share_page_service->get_share_link($code);
        $this->share_info = $share_res;
        if (!$share_res) return FALSE;

        //如果存在密码
        if ($share_res['password']) {
            //存在分享密码再判断有无密码验证过
            $share_check = $this->session->userdata('share_check');
            if (!$share_check || $share_check != $code) {
                //判断是否是分享者本人访问
                //$user = $this->session->userdata('__USER__');
                $this->load->service("login_service");
                $user_id = $this->login_service->get_user_info('id');

                //如果不存在用户或者用户不是本人则转跳至密码页
                if (!$user_id || ($user_id != $share_res['uid'])) {
                    return redirect('/share_check?code=' . $code);
                }
            }
        }

        return TRUE;
    }

    /**
     * 分享文件页
     * @param $code 分享码
     * @return bool
     */
    public function index($code="") {

        /*
        if($this->agent->is_mobile()){
            $platform = $this->input->get("platform");
            redirect("/m/download.html?".$code."#index/index?code=".$code."&platform=".$platform);
        }*/
        $data['code'] = $code;
        $data['name'] = $this->share_info['name'];
        //如果信息或code不存在
        if (! $this->status) {
            $data['error'] = '该链接无效，请联系文件所有者重新分享!';
            $this->template->view('share/home.tpl', $data);
            return FALSE;
        }

        //记录访问次数 本人除外
        //$user = $this->session->userdata('__USER__');
        $this->load->service("login_service");
        $user_id = $this->login_service->get_user_info('id');

        $isUser = FALSE;
        //文件拥有者访问
        if ($user_id && ($user_id == $this->share_info['uid'])) $isUser = TRUE;

        //第三方,更新统计数
        if (! $isUser)
            $this->share_page_service->update_count($this->share_info['id'], 1);

        $this->template->view('share/home.tpl', $data);
    }

    /**
     * 获取分享
     */
    public function get_share() {
        if (!$this->status) Common::ajax_return(7104);

        $share_list_result = $this->share_page_service->get_share_list($this->share_info['id']);
        $share_list_count = count($share_list_result);//分享文件个数

        if (!$share_list_result) Common::ajax_return(7104);

        $share_name = $this->share_info['name'];//分享名称
        //$share_type = 0;//1文件 2文件夹 3目录
        if ($share_list_count > 1) {
            $share_type = 3;//目录 可能是多文件夹、多文件、文件和文件夹混合
            $share_name .= '等';
        } else {
            $share_type = $share_list_result[0]['type'];
        }

        $folder_uuid_arr = array();
        $file_uuid_arr = array();

        //分类
        foreach ($share_list_result as $v) {
            if ($v['type'] == 2) {
                $folder_uuid_arr[] = $v['fid'];
            } else {
                $file_uuid_arr[] = $v['fid'];
            }
        }
        $folder_data_arr = array();
        $file_data_arr = array();
        $isPack = true;

        //文件夹id不为空
        if (!empty($folder_uuid_arr)) {
            $where = array(
                "deleted" => 0,
                "access_denied" => 0
            );
            if (count($folder_uuid_arr) == 1) {
                $where['id'] = $folder_uuid_arr[0];
            } else {
                $where['id'] = $folder_uuid_arr;
            }
            $folder_data_list = $this->user_files_service->get_folder_list($this->share_info['uid'], FALSE, "", "name", "asc", "id,id as fid,name,creation_ts,modify_ts,access_denied", $where);
            if(!empty($folder_data_list) && isset($folder_data_list['rows']))
            {
                foreach ($folder_data_list['rows'] as $v) {
                    $folder_data_arr[] = $v;
                }
            }

        }

        //文件id不为空
        if (!empty($file_uuid_arr)) {
            $where = array(
                "deleted" => 0,
                "access_denied" => 0
            );
            if (count($file_uuid_arr) == 1) {
                $where['id'] = $file_uuid_arr[0];
            } else {
                $where['id'] = $file_uuid_arr;
            }
            $file_data_list = $this->user_files_service->get_file_list($this->share_info['uid'], FALSE, FALSE, "", $where);
            if(!empty($file_data_list['rows']))
            {
                foreach ($file_data_list['rows'] as $v) {
                    $v['type'] = 1;
                    $v['fid'] = $v['id'];
                    if(isset($v['size']))
                    {
                        $v['data_size'] = Common::get_file_size($v['size']);
                    }
                    $file_data_arr[] = $v;
                }
            }
        }

        //组合
        $f_result = array_merge($folder_data_arr, $file_data_arr);
        if (!$f_result) {
            Common::ajax_return(7104);
        }

        //总数
        $f_count = count($f_result);
        if ($f_count == 0 && ($f_count != $share_list_count)) {
            //此错误优先级比较高
            Common::ajax_return(7104);
        }
        $data = array(
            'f_data' => $f_result,
            'f_count' => count($f_result)
        );
        $share_data = $this->template->view('share/data.tpl', $data, true);
        $share_data = $this->str_html($share_data);
        $data = array(
            'share_name' => $share_name,
            'share_type' => $share_type,
            'share_data' => $share_data
        );
        Common::ajax_return(0,NULL,$data,FALSE);
        /****************************** 文件夹或文件列表 暂时不做**************************************/

       // header("Content-Type: text/html; charset='utf-8'");
        //echo json_encode($data);

    }
    public function str_html($html)
    {
       return  strtr($html, array('<'=>'\u003C',">"=>'\u003E'));
    }
    /**
     * 进入文件夹获取数据
     */
    public function get_data() {
        if (!$this->status) Common::ajax_return(7104);

        $fid = (int)$this->input->get('fid');//文件uuid
        if (!$fid) Common::ajax_return(7104);

        $share_list_result = $this->share_page_service->get_share_list($this->share_info['id'], 2);
        if (!$share_list_result) Common::ajax_return(7104);
        $share_list_count = count($share_list_result);//分享的文件夹个数
        if ($share_list_count < 1) Common::ajax_return(7104); //无分享的文件夹

        //当前访问的文件夹是否可访问且未删除
        $p_folder = $this->share_page_service->get_folder_info($this->share_info['uid'], $fid);
        if (!$p_folder) Common::ajax_return(7104);
        $paths = explode(',', $p_folder['path']);
        array_push($paths, (string)$fid);
        $in_path = FALSE;
        //文件夹是否在祖父级分享的目录里面
        foreach ($share_list_result as $key => $value) {
            $in_path = in_array($value['fid'], $paths);
            //如果是分享的目录的子孙目录
            if ($in_path) {
                //记录路径
                foreach ($paths as $k => $v) {
                    if ($v != $value['fid']) {
                        unset($paths[$k]);
                        continue;
                    }
                    break;
                }
                //重新排序路径的id
                sort($paths);
                break;
            }
        }
        //如果不是在path目录
        if (!$in_path) {
            return Common::ajax_return(7104);
        }

        //首目录
        if ($paths[0] == $fid) {
            $back_path = "/";
        } else {
            $back_path = $p_folder['pid'];
        }

        //取得所有目录的信息
        $field = "id,pid,id as fid,name,access_denied,deleted,creation_ts";
        $folders_info = $this->share_page_service->get_folder_path("", $paths, $field);

        if (empty($folders_info)) Common::ajax_return(7104);
        $path[] = array("fid" => "/");
        foreach ($folders_info as $key => $value) {
            //如果目录有删除或者禁用
            if (($value['deleted'] == 1) || ($value['access_denied'] == 1)) {
                return Common::ajax_return(7104);
            }
            unset($value['access_denied'], $value['deleted']);
            $path[] = $value;
        }

        $file_result = $this->user_files_service->get_list($this->share_info['uid'], $fid, "", "name", "asc", array("deleted" => 0, "access_denied" => 0));

        //取得文件夹的信息
        $folder_data_arr = array();
        if ($file_result['folders']) {
            foreach ($file_result['folders'] as $v) {
                $v['fid'] = $v['id'];
                $folder_data_arr[] = $v;
            }
        }

        //取得文件信息
        $file_data_arr = array();
        if ($file_result['files']) {
            foreach ($file_result['files'] as $v) {
                $v['fid'] = $v['id'];
                $v['type'] = 1;
                if(isset($v['size']))
                {
                    $v['data_size'] = Common::get_file_size($v['size']);
                }
                $file_data_arr[] = $v;
            }
        }

        //组合
        $f_result = array_merge($folder_data_arr, $file_data_arr);
        //if(! $f_result) self::ret_error();

        $data = array(
            'share_path' => $path,
            'back_path' => $back_path,
            'count' => count($path) - 1
        );

        $share_path = $this->template->view('share/path.tpl', $data, TRUE);
        $data = array(
            'f_data' => $f_result,
            'f_count' => count($f_result)
        );

        //die(json_encode($data));
        $share_data = $this->template->view('share/data.tpl', $data, true);
        $share_path = $this->str_html($share_path);
        $share_data = $this->str_html($share_data);
        $data = array(
            'share_path' => $share_path,
            'share_data' => $share_data
        );

        Common::ajax_return(0,NULL,$data,FALSE);
        //echo json_encode($data);
    }

    /**
     * 生成文件/文件夹结果,传递给服务器
     * 添加code参数目的是防止窜行下载
     */
    public function create_struct() {
        $infos = $this->input->post('data', TRUE);
        $code = $this->input->post('code', TRUE);

        if (empty($infos) || empty($code))
            self::ret_error(1, "参数缺省");

        //是否有分享链接
        $share_res = $this->share_page_service->get_share_link($code);
        if (empty($share_res))
            self::ret_error(1, "分享代码信息出错");

        //是否有分享列表
        $share_list_result = $this->share_page_service->get_share_list($share_res['id']);
        if (empty($share_res))
            self::ret_error(1, "分享列表信息出错");

        $dl_name = '';  //下载包的名称

        $top_file = '';  //顶级首目录文件
        $file_list = '';  //子孙目录及文件
        $result_data = array();  //data部分
        $children_files = array();  //子孙文件
        $top_files_list = array();  //顶级目录的文件
        $suffix = "exe";

        $this->load->library('traces');  //轨迹类

        //有文件
        if (isset($infos['files'])) {
            if ((! isset($infos['folders'])) && (count($infos['files']) == 1)) $single = TRUE;  //是否单文件
            $top_files_list = $this->share_page_service->get_files_info($share_res['uid'], $infos['files']);

            //单文件
            if (isset($single)) {
                //如果文件不可控
                if (! $top_files_list) self::ret_error(1, "文件权限受限,不可下载");
                $single_file = array(
                    'name' => $top_files_list[0]['name']."_".$top_files_list[0]['ext_name'].".".$suffix,
                    'guid' => $top_files_list[0]['guid']
                );
                echo json_encode($single_file);

                $single_file = array(
                    array('file_id' => $infos['files'][0])
                );
                Traces::trace_download_batch($single_file, Traces::EVENT_DOWNLOAD_SECURE_FILE);
                $this->share_service->update_downloaded_batch($share_res['uid'], $single_file);
                return TRUE;
            }

            if (empty($dl_name)) $dl_name = $top_files_list[0]['name'];  //下载包的名称
            $top_file = $this->create_files($top_files_list, $suffix);
        }

        //有文件夹
        if (isset($infos['folders'])) {
            $sub_folders = $infos['folders'];  //提交的文件夹id组

            $top_path_id = array();  //分享列表的文件夹id
            //取出顶级文件夹
            foreach ($share_list_result as $keys => $values) {
                if ($values['type'] == 2) $top_path_id[] = $values['fid'];
            }
            //分享码不存在分享的文件夹
            if (empty($top_path_id)) self::ret_error(1, "分享码信息错误");

            $parent_path = '';  //当前下载的父级路径
            $in_path = TRUE;  //标记,默认其路径是在分享中
            //判断其或其父级是否在分享列表中
            foreach ($sub_folders as $key => $sub_id) {
                //当前查询的文件夹是否可访问且未删除
                $share_folder = $this->share_page_service->get_folder_info($share_res['uid'], $sub_id);
                if (! $share_folder) self::ret_error(1, "分享列表信息错误");
                if (empty($parent_path)) $parent_path = $share_folder['path'];  //父级路径
                if (empty($dl_name)) $dl_name = $share_folder['name'];  //下载包的名称

                //文件夹本身就是最顶层
                if (empty($share_folder['pid'])) {
                    //本身不在分享中
                    if (! in_array($share_folder['id'], $top_path_id)) {
                        $in_path = FALSE;
                        break;
                    }

                } else {
                    $p_path = $this->share_page_service->path_in_fids($share_folder['path'], $top_path_id, $share_folder['id']);
                    if (! $p_path) {
                        $in_path = FALSE;  //父级不在分享中
                        break;
                    }
                }
            }
            if (! $in_path) self::ret_error(1, "文件夹信息传输错误");

            //所有的子目录及本身的信息
            $folder_children = $this->share_page_service->get_folder_children($share_res['uid'], $sub_folders);
            //文件夹名称 --> key => value,路径名时用到
            $name_children = array();
            foreach ($folder_children as $keys => $values) {
                $name_children[$values['id']] = $values['name'];
            }

            //拒绝访问的目录
            $folder_access_denied = array();
            foreach ($folder_children as $key => $fd) {
                if ($fd['access_denied'] == 1) {
                    $folder_access_denied[] = $fd['id'];
                }
            }

            //提取之后整理的文件夹
            $new_children = array();
            foreach ($folder_children as $keys => $child) {
                $cre_path1 =  $child['path'].",".$child['id'];
                //剃除父级路径,只取当前下载的路径新建文件夹
                $cre_path2 = str_replace($parent_path.",", "", $cre_path1);
                $cre_path = explode(",", $cre_path2);
                //path文件夹路径名
                $f_path_name = "";
                foreach ($cre_path as $key => $pt_id) {
                    //此目录的父级包含在access_denied=1中
                    if (in_array($pt_id, $folder_access_denied)) {
                        continue 2;  //跳过本次记录
                    }
                    $f_path_name .= DIRECTORY_SEPARATOR.$name_children[$pt_id];
                }

                $new_children[] = array(
                    'id' => $child['id'],
                    'level' => count($cre_path),  //层级
                    'type' => 2,
                    'name' => $child['name'],
                    'path' => $f_path_name
                );
            }

            //当前和子孙目录的id
            $children_ids = array();
            foreach ($folder_children as $key => $value) {
                $children_ids[] = $value['id'];
            }

            //所有子孙目录的文件
            $children_files = $this->share_page_service->get_folder_files($share_res['uid'], $children_ids);
            $file_list = $this->data_assemble($children_files, $new_children);
        }

        if ((! empty($top_file)) && (! empty($file_list))) {
           $result_data = array_merge((array)$top_file, (array)$file_list);
        } else {
            //顶级目录不为空
            if (! empty($top_file)) {
                $result_data = $top_file;
            } else if (! empty($file_list)) {
                $result_data = $file_list;
            }
        }

        if (empty($result_data)) self::ret_error(1, "选择下载的文件生成失败");
        if (empty($children_files) && empty($top_files_list)) self::ret_error(1, "所选项中没有文件");

        $zip_name_format = $this->lang->line('download_zip_name');
        $zip_name = sprintf($zip_name_format, $dl_name);

        $result = array(
            'name' => $zip_name,
            'data' => $result_data
        );

        // 处理轨迹
        $file_trace_list = array_merge($top_files_list, $children_files);  //合并顶部文件及目录下的文件
        $list_chunk = array_chunk($file_trace_list, 50);  //拆分成每50条上组的数组,轨迹用
        foreach ($list_chunk as $keys => $values) {
            Traces::trace_download_batch($values, Traces::EVENT_DOWNLOAD_SECURE_FILE);
            $this->share_service->update_downloaded_batch($share_res['uid'], $values);
        }

        $this->load->service("login_service");
        $user_id = $this->login_service->get_user_info('id');
        $isUser = FALSE;
        //文件拥有者访问
        if ($user_id && ($user_id == $share_res['id'])) $isUser = TRUE;

        //第三方,更新下载统计数
        if (! $isUser)
            $this->share_page_service->update_count($share_res['id'], 2);

        echo json_encode($result);
    }

    /**
     * 将文件组合到文件夹中
     * @param $files 文件
     * @param $folders 文件夹
     * @param string $ext 文件后缀
     * @return array
     */
    public function data_assemble($files, $folders, $ext="exe") {
        $fils_list = array();
        //文件遍历
        foreach ($files as $keys => $values) {
            $fils_list[$values['folder_id']][] = array(
                'type' => 1,
                'name' => $values['name']."_".$values['ext_name'].".".$ext,
                'guid' => $values['guid']
            );
        }

        $folders_list = array();
        //文件夹遍历
        foreach ($folders as $keys => $values) {
            $new_folder = array(
                'type' => 2,
                'name' => $values['name'],
                'path' => $values['path']
            );
            if (isset($fils_list[$values['id']])) {
                $new_folder['files'] = $fils_list[$values['id']];
            }
            $folders_list[] = $new_folder;  //[$values['level']]
        }

        return $folders_list;
    }

    /**
     * 组合顶层文件
     * @param $files
     * @param string $ext 后缀名
     * @return array
     */
    public function create_files($files, $ext="exe") {
        $files_list = array();
        //文件遍历
        foreach ($files as $keys => $values) {
            $files_list[] = array(
                'type' => 1,
                'name' => $values['name']."_".$values['ext_name'].".".$ext,
                'guid' => $values['guid']
            );
        }

        return $files_list;
    }

    /**
     * 获取文件下载地址
     */
    public function get_download_link()
    {
        $id = $this->input->get("id",TRUE);
        $type = (int)$this->input->get("type",TRUE);
        $code = $this->input->get('code', TRUE);
        if(empty($id) || empty($type) || empty($code))
        {
            Common::ajax_return(1003);
        }
        //下载链接存活时间
        $download_exp = $this->config->item("download_expire_time");
        //检查对应的分享链接
        $share_res = $this->share_page_service->check_file_in_share($id,$code);
        if (empty($share_res))
        {
            Common::ajax_return(1003);
        }
        $data = $this->user_files_service->get_all_file_info($id,array("deleted" => 0, "access_denied" =>0),array(),array("type"=>$type),"uid,name,size,ext_name,source_guid","","guid");
        if(empty($data) || empty($data['guid']))
        {
            Common::ajax_return(7001);
        }
        $file_guid = $data['guid'];

        $ext = $type == 1 ? ".exe" : ".ek";

        $file_name = $data['name']."_".$data['ext_name'].$ext;
        $test_source = "./resources/file/".$data['source_guid'].".tmp";
        //$this->share_service->update_downloaded_batch($data['uid'],array($id));
        $this->share_page_service->update_download($id,$code);
        if (ENVIRONMENT !="development")
        {
            $link_id = Common::download_link($file_guid, $code);
            $data = json_encode(array("guid"=>$file_guid,"name"=>rawurlencode($file_name)));
            $redis = new Redis();
            $connect = $redis->connect($this->config->item("host","redis"),$this->config->item("port","redis"),$this->config->item("timeout","redis"));
            if(!$connect)
            {
                Common::ajax_return(1019);
            }
            else
            {
                $this->user_files_service->update_file_info(array("id"=>$id),array("downloaded"=>1));
                $set = $redis->setex($link_id,$download_exp,$data);
                if(!$set)
                {
                    Common::ajax_return(1019);
                }
            }

            $file = array(
                'id' => $id
            );
            Traces::trace_download_batch(array($file), Traces::EVENT_DOWNLOAD_SECURE_FILE);
            Common::ajax_return(0,NULL,array("url"=>"/d?id=".$link_id),FALSE);
        }
        //本地测试环境
        else if(file_exists($test_source))
        {
            Common::ajax_return(0,NULL,array("url"=>"/test/download?id=".$data['source_guid']."&name=".urlencode($file_name)),FALSE);
        }
        else
        {
            Common::ajax_return(1004);
        }
    }




    /**
     * @param int $code 错误代码
     * @param string $error 错误提示信息
     */
    static function ret_error($code = 1, $error = '该链接无效，请联系文件所有者重新分享!'){
        $data = array(
            'ret'       => $code,
            'error'     => $error
        );

        header("Content-Type: application/json; charset=utf-8");
        die(json_encode($data));
    }
 }
 
/* End of file share_page.php */
/* Location: ./application/controllers/share_page.php */